﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;

namespace ICSharpCode.AvalonEdit.Editing
{
    internal class AccentuateLayer : Layer, IWeakEventListener
    {
        private readonly TextArea _textArea;

        public AccentuateLayer(TextArea textArea)
            : base(textArea.TextView, KnownLayer.Selection)
        {
            IsHitTestVisible = false;
            _textArea = textArea;
            TextViewWeakEventManager.VisualLinesChanged.AddListener(textView, this);
            TextViewWeakEventManager.ScrollOffsetChanged.AddListener(textView, this);
        }

        bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            if (managerType == typeof (TextViewWeakEventManager.VisualLinesChanged)
                || managerType == typeof (TextViewWeakEventManager.ScrollOffsetChanged))
            {
                InvalidateVisual();
                return true;
            }
            return false;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            var geoBuilder = new BackgroundGeometryBuilder
                {
                    AlignToMiddleOfPixels = true,
                    CornerRadius = _textArea.AccentuateCornerRadius,
                };

            if (_textArea.Matches != null)
            {
                var firstVisualLine = _textArea.TextView.VisualLines.First();
                var lastVisualLine = _textArea.TextView.VisualLines.Last();
                var matches =
                    _textArea.Matches.
                              Where(
                                  m =>
                                  (m.Index >= firstVisualLine.FirstDocumentLine.Offset
                                   && m.Index <= lastVisualLine.LastDocumentLine.EndOffset)
                                  || (m.Index + m.Length >= firstVisualLine.FirstDocumentLine.Offset
                                      && m.Index + m.Length <= lastVisualLine.LastDocumentLine.EndOffset)).ToList();
                foreach (var segment in matches.Select(m => new SimpleSegment(m.Index, m.Length)))
                {
                    geoBuilder.AddSegment(textView, segment, true);
                }
            }

            var geometry = geoBuilder.CreateGeometry();
            if (geometry != null)
            {
                drawingContext.DrawGeometry(_textArea.AccentuateBrush, _textArea.AccentuateBorder, geometry);
            }
        }
    }
}
